package com.maimang.platform.config;

import com.maimang.platform.annotation.PassToken;
import com.maimang.platform.annotation.UserLoginToken;
import com.maimang.platform.base.Result;
import com.maimang.platform.common.entity.SysUser;
import com.maimang.platform.common.utils.JwtUtils;
import com.maimang.platform.common.utils.cache.EHCacheUtil;
import com.maimang.platform.common.utils.http.ServletUtils;
import com.maimang.platform.enums.Status;
import com.maimang.platform.lang.StringUtils;
import com.maimang.platform.tool.ToolJackson;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * @author Rocky
 * @version 1.0.0
 * @classname JwtApiInterceptor
 * @description jwt接口授权拦截器
 * @date 2019-01-23 23:26
 * @email jintaozhao@qq.com
 */
public class JwtApiInterceptor implements HandlerInterceptor {

	/**
	 * 在请求处理前调用（Controller方法调用之前）
	 * 用缓存为什么用还用jwt? -- 可以减轻redis服务器压力以及jwt的计算压力，从业务逻辑里取本地缓存的用户信息
	 *
	 * @param request
	 * @param response
	 * @param handler
	 * @return
	 * @throws Exception
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		/*验证token*/
		String token = request.getHeader("token");

		// 如果不是映射到方法直接通过
		if (!(handler instanceof HandlerMethod)) {
			return true;
		}
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		Method method = handlerMethod.getMethod();
		//检查是否有PassToken注释，有则跳过认证
		if (method.isAnnotationPresent(PassToken.class)) {
			PassToken passToken = method.getAnnotation(PassToken.class);
			if (passToken.required()) {
				return true;
			}
		}

		if (method.isAnnotationPresent(UserLoginToken.class)) {
			UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
			if (userLoginToken.required()) {
				// 执行认证
				if (StringUtils.isEmpty(token)) {
					ServletUtils.renderString(response, Result.FAIL(Status.token_without).toJson());
					return false;
				}
				// 先从缓存中取,缓存里已经能取到,说明token是正确有效的,缓存有效时间和token的一样
				Object cache = EHCacheUtil.get(token);
				if (cache != null) {
					return true;
				}
				// 缓存中不能取到，那就处理后将数据缓存下来
				String verifyStr = JwtUtils.verifyToken(token);
				if (StringUtils.isNotEmpty(verifyStr)) {
					// 缓存用户token信息
					long liveTime = JwtUtils.getLiveTime(token);
					// 即将过期
					if (liveTime < 2000) {
						// 将验证结果渲染到客户端
						ServletUtils.renderString(response, Result.FAIL(Status.token_invalid).toJson());
						return false;
					}
					SysUser user = ToolJackson.toObject(verifyStr, SysUser.class);
					EHCacheUtil.setValue("jwt", token, user, (int) liveTime / 1000);
				} else {
					// 将验证结果渲染到客户端
					ServletUtils.renderString(response, Result.FAIL(Status.token_invalid).toJson());
					return false;
				}
			}
		}

		return true;
	}

	/**
	 * 请求处理之后进行调用，但是在视图被渲染之前（Controller方法调用之后）
	 *
	 * @param request
	 * @param response
	 * @param handler
	 * @param modelAndView
	 * @throws Exception
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

	}

	/**
	 * 在整个请求结束之后被调用，也就是在DispatcherServlet渲染了对应的视图之后执行（主要是用于进行资源清理工作）
	 *
	 * @param request
	 * @param response
	 * @param handler
	 * @param ex
	 * @throws Exception
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

	}
}
